/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.das.commonmodel.entity.object.increment.merger;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlrule.cm.CommonDataTypeControlRule;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.basic.entity.ControlRuleValue;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.cm.CommonDataTypeControlRuleDef;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.entity.GspCommonDataType;
import com.inspur.edp.cef.designtime.api.entity.increment.AddedEntityIncrement;
import com.inspur.edp.cef.designtime.api.entity.increment.CommonEntityIncrement;
import com.inspur.edp.cef.designtime.api.entity.increment.ModifyEntityIncrement;
import com.inspur.edp.cef.designtime.api.entity.increment.merger.DataTypeIncrementMerger;
import com.inspur.edp.cef.designtime.api.increment.merger.MergeUtils;
import com.inspur.edp.cef.designtime.api.increment.property.BooleanPropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.ObjectPropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.PropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.StringPropertyIncrement;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.collection.GspObjectCollection;
import com.inspur.edp.das.commonmodel.controlrule.CmEntityControlRule;
import com.inspur.edp.das.commonmodel.entity.GspCommonObject;
import com.inspur.edp.das.commonmodel.entity.object.GspCommonObjectType;
import com.inspur.edp.das.commonmodel.json.CommonModelNames;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import lombok.var;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;

public class CommonObjectIncrementMerger extends DataTypeIncrementMerger {
    private static Logger logger = LoggerFactory.getLogger(CommonObjectIncrementMerger.class);
    public CommonObjectIncrementMerger(){
        super();
    }

    public CommonObjectIncrementMerger(boolean includeAll){
        super(includeAll);
    }
    @Override
    protected void mergeExtendModifyIncrement(GspCommonDataType extendDataType,GspCommonDataType rootDataType, ModifyEntityIncrement extendIncrement, ModifyEntityIncrement baseIncrement, CommonDataTypeControlRule rule, CommonDataTypeControlRuleDef def) {
        GspCommonObject extendObj = (GspCommonObject) extendDataType;
        GspCommonObject rootObj = (GspCommonObject) rootDataType;
        //region child entity
        mergeChildObjs(extendObj,rootObj, extendIncrement, baseIncrement, rule, def);
        //endregion

        //region extendInfo
        mergeExtendObjectInfo(extendObj, extendIncrement, baseIncrement, rule, def);
        //endregion

    }


    //region child entity
    private void mergeChildObjs(GspCommonObject extendObj, GspCommonObject rootObj, ModifyEntityIncrement extendIncrement, ModifyEntityIncrement baseIncrement, CommonDataTypeControlRule rule, CommonDataTypeControlRuleDef def) {
        var extendChildObjs = extendIncrement.getChildEntitis();
        var baseChildObjs = baseIncrement.getChildEntitis();
        if (extendChildObjs.size() < 1 && baseChildObjs.size() < 1)
            return;
        var merger = getChildObjectMerger();

        ArrayList<String> updateObjs = new ArrayList<>();
        logger.error(getMessage(extendObj));
        logger.error("同步的子表数量为："+baseChildObjs.size());
        for (var childObjPair : baseChildObjs.entrySet()) {
            CommonEntityIncrement childEntityIncrement = childObjPair.getValue();
            switch (childEntityIncrement.getIncrementType()) {
                case Added:
                    mergeAddedObj(extendObj, (AddedEntityIncrement) childEntityIncrement, extendChildObjs, rule, def);
                    break;
                case Deleted:
                    extendObj.getContainChildObjects().remove(childEntityIncrement.getId());
                    break;
                case Modify:
                    dealModifyChild(extendObj,rootObj, (ModifyEntityIncrement) childEntityIncrement, extendChildObjs, rule, def);
            }

        }
    }

    private String getMessage(GspCommonObject extendObj){
        StringBuilder builder=new StringBuilder();
        IGspCommonModel model=extendObj.getBelongModel();
        if(model==null){
            String modelCode=model.getCode();
            String modelName=model.getName();
            String modelID=model.getID();
            builder.append("开始同步ID为：").append(modelID).append(",编号为：").append(modelCode).append(",名称为：").append(modelName).append("的元数据的子表信息！");
          return   builder.toString();
        }
        return  builder.append("开始同步ID为：").append(extendObj.getID()).append(",编号为：").append(extendObj.getCode()).append(",名称为：").append(extendObj.getName()).append("的节点对象的的子表信息！").toString();
    }
    private void mergeAddedObj(
            GspCommonObject extendObj,
            AddedEntityIncrement childEntityIncrement,
            HashMap<String, CommonEntityIncrement> extendChildEntitis,
            CommonDataTypeControlRule rule,
            CommonDataTypeControlRuleDef def) {

        if (isAllowAddChildObj(rule, def)) {
            IGspCommonObject commonObject=(IGspCommonObject) childEntityIncrement.getAddedDataType();
            if(isAddNewChildObject(extendObj,commonObject)) {
                extendObj.getContainChildObjects().add(commonObject);
            }
        }

    }
    private boolean isAddNewChildObject(GspCommonObject extendObj, IGspCommonObject childObject ) {
        GspObjectCollection containChildObjects = extendObj.getContainChildObjects();
        IGspCommonObject commonObject=getObjectById(childObject.getID(),containChildObjects);
        if(commonObject!=null){
            StringBuilder builder=new StringBuilder();
            builder.append("当前ID为：").append(extendObj.getID()).append(",名称为：").append(extendObj.getName()).append("的节点对象上已经存在ID为：").append(childObject.getID()).append("名称为：").append(childObject.getName()).append("的子表!");
            logger.error(builder.toString());
        }
        return commonObject==null;
    }
    private IGspCommonObject getObjectById(String id, GspObjectCollection collection){
        for (IGspCommonObject item : collection) {
            if (id.equals(item.getID())) {
                return item;
            }
        }
        return null;
    }
    private boolean isAllowAddChildObj(CommonDataTypeControlRule rule,
                                       CommonDataTypeControlRuleDef def) {
        switch (rule.getAddChildEntityControlRule().getControlRuleValue()) {
            case Allow:
                return true;
            case Forbiddon:
                return false;
            case Default:
                return def.getAddChildEntityControlRule().getDefaultRuleValue() == ControlRuleValue.Allow;
            default:
                throw new CAFRuntimeException("", "",
                        "不存在控规方式：" + rule.getAddChildEntityControlRule().getControlRuleValue(), null, ExceptionLevel.Error);
        }
    }


    private void dealModifyChild(
            GspCommonObject extendObj,
            GspCommonObject rootObj, ModifyEntityIncrement baseChildIncrement,
            HashMap<String, CommonEntityIncrement> extendIncrement,
            CommonDataTypeControlRule rule,
            CommonDataTypeControlRuleDef def) {
        var childObj = extendObj.getChildObjectById(baseChildIncrement.getId());
        IGspCommonObject rootChildObj = null;
        if(rootObj!=null)
            rootChildObj=rootObj.getChildObjectById(baseChildIncrement.getId());
        if (childObj == null) {
            if(rootChildObj!=null)
                childObj=rootChildObj.clone(extendObj);
            if (childObj == null)
                throw new RuntimeException("节点" + extendObj.getCode() + "上没有找到子节点" + baseChildIncrement.getId());
            extendObj.getContainChildObjects().add(childObj);
        }
        ModifyEntityIncrement extendObjIncrement = null;
        if (extendIncrement.containsKey(baseChildIncrement.getId()))
            extendObjIncrement = (ModifyEntityIncrement) extendIncrement.get(baseChildIncrement.getId());
        var merger = getChildObjectMerger();
        if (extendObjIncrement == null)
            extendObjIncrement = new ModifyEntityIncrement();
        CmEntityControlRule childObjRule = (CmEntityControlRule) rule.getChildRules().get(CommonModelNames.ChildObject).get(baseChildIncrement.getId());
        merger.merge((GspCommonDataType) childObj, (GspCommonDataType) rootChildObj,extendObjIncrement, baseChildIncrement, childObjRule, def);
    }

    protected CommonObjectIncrementMerger getChildObjectMerger() {
        return new CommonObjectIncrementMerger(includeAll);
    }

    //endregion

    protected void mergeExtendObjectInfo(GspCommonObject extendObj, ModifyEntityIncrement extendIncrement, ModifyEntityIncrement baseIncrement, CommonDataTypeControlRule rule,
                                         CommonDataTypeControlRuleDef def) {

    }


    @Override
    protected void dealExtendChangeProp(GspCommonDataType extendDataType, HashMap<String, PropertyIncrement> extendIncrement, String key, PropertyIncrement increment) {

        GspCommonObject obj = (GspCommonObject) extendDataType;
        switch (key) {
            case CommonModelNames.RefObjectName:
                String mergedRefObjectName = MergeUtils.getStringValue(CommonModelNames.RefObjectName, (StringPropertyIncrement) increment, extendIncrement, null, null);
                obj.setRefObjectName(mergedRefObjectName);
                return;
            case CommonModelNames.ObjectType:
                GspCommonObjectType mergedObjectType = MergeUtils.getObjectValue(CommonModelNames.ObjectType, (ObjectPropertyIncrement) increment, extendIncrement, null, null);
                obj.setObjectType(mergedObjectType);
                return;
            case CommonModelNames.OrderbyCondition:
                String mergedOrderbyCondition = MergeUtils.getStringValue(CommonModelNames.OrderbyCondition, (StringPropertyIncrement) increment, extendIncrement, null, null);
                obj.setOrderbyCondition(mergedOrderbyCondition);
                return;
            case CommonModelNames.FilterCondition:
                String mergedFilterCondition = MergeUtils.getStringValue(CommonModelNames.FilterCondition, (StringPropertyIncrement) increment, extendIncrement, null, null);
                obj.setFilterCondition(mergedFilterCondition);
                return;
            case CommonModelNames.IsReadOnly:
                boolean mergedReadonly = MergeUtils.getBooleanValue(CommonModelNames.IsReadOnly, (BooleanPropertyIncrement) increment, extendIncrement, null, null);
                obj.setIsReadOnly(mergedReadonly);
                return;
            case CommonModelNames.IsVirtual:
                boolean mergedIsVirtual = MergeUtils.getBooleanValue(CommonModelNames.IsVirtual, (BooleanPropertyIncrement) increment, extendIncrement, null, null);
                obj.setIsVirtual(mergedIsVirtual);
                return;
            case CommonModelNames.BelongModelID:
                String mergedBelongModelID = MergeUtils.getStringValue(CommonModelNames.BelongModelID, (StringPropertyIncrement) increment, extendIncrement, null, null);
                obj.setBelongModelID(mergedBelongModelID);
                return;
            case CommonModelNames.StateElementID:
                String mergedStateElementID = MergeUtils.getStringValue(CommonModelNames.StateElementID, (StringPropertyIncrement) increment, extendIncrement, null, null);
                obj.setStateElementID(mergedStateElementID);
                return;
        }
        dealCommonObjChangeProp(obj, extendIncrement, key, increment);
    }


    protected void dealCommonObjChangeProp(GspCommonObject obj, HashMap<String, PropertyIncrement> extendIncrement, String key, PropertyIncrement increment) {
    }

}
